import { _decorator, IVec2, tween, Tween, Vec3 } from 'cc'
import { EntityManager } from '../../Base/EntityManager'
import { EntityTypeEnum, IBullet } from '../../Common'
import { EntityStateEnum, EventEnum } from '../../Enum'
import DataManager from '../../Global/DataManager'
import EventManager from '../../Global/EventManager'
import { ObjectPoolManager } from '../../Global/ObjectPoolManager'
import { rad2Angle } from '../../Utils'
import { ExplosionManager } from '../Explosion/ExplosionManager'
import { BulletStateMachine } from './BulletStateMachine'
const { ccclass } = _decorator

@ccclass('BulletManager')
export class BulletManager extends EntityManager {
  id: number
  type: EntityTypeEnum
  private targetPos: Vec3
  private tw: Tween<unknown>

  init(data: IBullet) {
    this.type = data.type
    this.id = data.id
    this.fsm = this.addComponent(BulletStateMachine)
    this.fsm.init(data.type)
    this.state = EntityStateEnum.Idle
    // 初始化时位置在（0,0）,后端传过来的位置在（-150, -150），先隐藏,避免闪烁问题
    this.node.active = false
    this.targetPos = undefined

    EventManager.Instance.on(EventEnum.ExplosionBorn, this.handleExplosionBorn, this)
  }

  handleExplosionBorn(id: number, { x, y }: IVec2) {
    if (id !== this.id) return

    // 从对象池中获取爆炸节点
    const explosion = ObjectPoolManager.Instance.get(EntityTypeEnum.Explosion)

    // 如果能获取到组件，则直接使用，否则添加组件
    const em = explosion.getComponent(ExplosionManager) || explosion.addComponent(ExplosionManager)
    em.init(EntityTypeEnum.Explosion, { x, y })

    // 移除事件
    EventManager.Instance.off(EventEnum.ExplosionBorn, this.handleExplosionBorn, this)
    // 移除bulletMap中的子弹
    DataManager.Instance.bulletMap.delete(this.id)
    // 回收对象池 == 销毁子弹
    ObjectPoolManager.Instance.ret(this.node)
  }

  render(data: IBullet) {
    this.renderPosition(data)
    this.renderDirection(data)
  }

  renderPosition(data: IBullet) {
    const { position } = data
    const newPos = new Vec3(position.x, position.y)
    if (!this.targetPos) {
      this.node.setPosition(newPos)
      this.targetPos = newPos
      this.node.active = true
    } else if (!this.targetPos.equals(newPos)) {
      // 因为newPos是后端传过来的，后端每隔100ms传一次，加这个判断是让这个renderPositon100ms执行一次
      this.tw?.stop()
      this.node.setPosition(this.targetPos)
      this.targetPos.set(newPos)
      this.tw = tween(this.node).to(0.1, { position: this.targetPos }).start()
    }
  }

  renderDirection(data: IBullet) {
    const { direction } = data
    // 计算子弹朝向
    const side = Math.sqrt(direction.x ** 2 + direction.y ** 2) // 斜边的长度
    const rad = direction.x > 0 ? Math.asin(direction.y / side) : Math.asin(-direction.y / side) + Math.PI
    const angle = rad2Angle(rad)
    this.node.setRotationFromEuler(0, 0, angle)
  }
}
